/*********************************************************************************
 *      Copyright:  (C) 2023 LingYun IoT System Studio
 *                  All rights reserved.
 *
 *       Filename:  sht20.c
 *    Description:  This file is temperature and relative humidity sensor SHT20 code.
 *                 
 *        Version:  1.0.0(2023年07月02日)
 *         Author:  Ling Yun <lingyun@email.com>
 *      ChangeLog:  1, Release initial version on "2023年07月02日 20时16分01秒"
 *                 
 ********************************************************************************/

/*
* Hardware connection:
*
*   Sht20 Module       RaspberryPi/IGKBoard
*      VCC      <----->      3.3V
*      SDA      <----->      SDA
*      SCL      <----->      SCL
*      GND      <----->      GND
*/


#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <linux/i2c-dev.h>
#include <stdint.h>
#include <time.h>
#include <errno.h>

#define SOFTRESET					0XFE
#define TRIGGER_TEMPERATURE_NO_HOLD	0xF3
#define TRIGGER_HUMIDITY_NO_HOLD	0XF5

static inline void msleep(unsigned long ms);
static inline void dump_buf(const char *prompt,uint8_t *buf,int size);
int sht2x_init(char *i2c_dev);
int	sht2x_get_serialnumber(int fd,uint8_t *serialnumber,int size);
int sht2x_get_temp_humidity(int fd,float *temp,float *rh);


int main (int argc, char **argv)
{
	int 	fd;
	float	temp;
	float	rh;
	uint8_t	serialnumber[8];

	if( argc !=2)
	{
		printf("This program used to do I2C test by sht20 temperature & humidity module.\n");
		printf("Usage:%s /dev/i2c-x\n",argv[0]);
		return 0;
	}

	fd = sht2x_init(argv[1]);
	if(fd < 0)
	{
		printf("SHT2x initialize failure\n");
		return 1;
	}

	if( sht2x_get_serialnumber(fd , serialnumber,8) < 0)
	{
		printf("SHT2x get serial number failure\n");
		return 2;
	}
	
	if(	sht2x_get_temp_humidity(fd,&temp,&rh) < 0)
	{
		printf("SHT2x get temperature and relative humidity failure\n");
		return 3;
	}

	printf("Temperature=%lf 'C relative humidity=%lf\n",temp,rh);
	close(fd);

	return 0;
} 

/*  ms级休眠函数  */
static inline void msleep(unsigned long ms)
{
	struct timespec cSleep;
	unsigned long ulTmp;

	cSleep.tv_sec = ms / 1000;
	if (cSleep.tv_sec == 0)
	{
		ulTmp = ms*10000;
		cSleep.tv_nsec = ulTmp * 100;
	}
	else
	{
		cSleep.tv_nsec = 0;
	}

	nanosleep(&cSleep,0);
}

/*  打印 buf值 */
static inline void dump_buf(const char *prompt,uint8_t *buf,int size)
{
	int i;

	if( !buf )
	{
		return ;
	}
	if(prompt)
	{
		printf("%s",prompt);
	}

	for(i=0;i<size;i++)
	{
		printf("%02x",buf[i]);
	}
	printf("\n");
	return;
}

/*  sht20命令复位  */
int sht2x_softreset(int fd)
{
	uint8_t 	buf[4];

	if(fd < 0)
	{
		printf("%s line [%d] %s[] get invalid input arguments\n",__FILE__,__LINE__,__func__);
		return -1;
	}

	/*  software reset SHT2x  */
	memset(buf,0,sizeof(buf));

	/*  按照手册命令表进行命令发送 并休眠需要的时间  */
	buf[0] = SOFTRESET;
	write(fd,buf,1);

	msleep(50);
	return 0;
}

/*  初始化sht20 设备新参为i2c总线节点  */
int sht2x_init(char *i2c_dev)
{
	int fd;

	if((fd=open(i2c_dev,O_RDWR)) < 0)
	{
		printf("i2c device open failed:%s\n",strerror(errno));
		return -1;
	}
	
	/*  set I2C mode and SHT2x slave address  */
	ioctl(fd, I2C_TENBIT, 0);    /*  Not 10-bit but 7-bit mode  */
	ioctl(fd, I2C_SLAVE, 0x40); /* set SHT20 slava address 0x40 */

	if( sht2x_softreset(fd) < 0)
	{
		printf("SHT2x softreset failure\n");
		return -2;
	}
	return fd;
}

/*  获取sht20的温度湿度值  */
int sht2x_get_temp_humidity(int fd,float *temp,float *rh)
{
	uint8_t	buf[4];

	if( fd<0 || !temp || !rh)
	{
		printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ );
		return -1;
	}

	/*  send trigger temperature measure command and read the data  */
	memset(buf,0,sizeof(buf));
	/*  发送非主机保持的温度测量命令  */
	buf[0]=TRIGGER_TEMPERATURE_NO_HOLD;
	write(fd,buf,1);

	/*  等待需要的时间 数据手册可知  */
	msleep(85);/*  datasheet: typ=66, max=85 */

	memset(buf,0,sizeof(buf));
	/*  读取三个字节的数据，最后一个字节为crc检验值  */
	read(fd,buf,3);
	dump_buf("Temperature sample data:",buf,3);
	/*  计算实际温度值 */
	*temp = 175.72 * (((((int) buf[0]) << 8) + (buf[1] & 0xfc)) / 65536.0) - 46.85;
	
	/*  send trigger humidity measure command and read the data  */
	memset(buf,0,sizeof(buf));
	/*  发送非主机保持的湿度测量命令  */
	buf[0] = TRIGGER_HUMIDITY_NO_HOLD;
	write(fd, buf, 1);

	msleep(29);/*  datasheet: typ=22, max=29 */ 
	memset(buf, 0, sizeof(buf));

	read(fd , buf, 3);
	dump_buf("Relative humidity sample data:",buf,3);
	/*  计算实际湿度值*/
	*rh = 125 * (((((int) buf[0]) << 8) + (buf[1] & 0xfc)) / 65536.0) - 6;
	
	return 0;
}

/*  获取sht20的唯一序列号 详情可以查看数据手册*/ 
int sht2x_get_serialnumber(int fd,uint8_t *serialnumber,int size)
{
	uint8_t	buf[4];

	if( fd<0 || !serialnumber || size!=8 )
	{
		printf("%s line [%d] %s() get invalid input arguments\n", __FILE__, __LINE__, __func__ );
		return -1;
	}
	
	/*  Read SerialNumber from Location 1  */
	memset(buf,0,sizeof(buf));
	buf[0] = 0xfa;  /*  command for readout on-chip memory  */
	buf[1] = 0x0f;  /*  on-chip memory address  */
	write(fd,buf,2);

	memset(buf,0,sizeof(buf));
	read(fd, buf, 4);

	serialnumber[5]=buf[0]; /*  Read SNB_3 */
	serialnumber[4]=buf[1]; /*  Read SNB_2 */
	serialnumber[3]=buf[2]; /*  Read SNB_1 */
	serialnumber[2]=buf[3]; /*  Read SNB_0 */

	/*  Read SerialNumber from Location 2 */
	memset(buf, 0, sizeof(buf) );
	buf[0]=0xfc;  /*  command for readout on-chip memory */
	buf[1]=0xc9;  /*  on-chip memory address */
	write(fd, buf, 2);
	
	memset(buf, 0, sizeof(buf) );
	read(fd, buf, 4);

	serialnumber[1]=buf[0]; /*  Read SNC_1 */
	serialnumber[0]=buf[1]; /*  Read SNC_0 */
	serialnumber[7]=buf[2]; /*  Read SNA_1 */
	serialnumber[6]=buf[3]; /*  Read SNA_0 */

	dump_buf("SHT2X serial number:",serialnumber,8);
	return 0;

}








